module registers (
    input wire clk,
    input wire rst,
    input wire [4:0] rs_1, rs_2, rt_1, rt_2,  //需要重命名的源寄存器号
    input wire [4:0] rd_1, rd_2,              //需要重命名的目标寄存器号
    input wire [31:0] imm_1, imm_2,
    input wire rob_save_direct_ctrl_1, rob_save_direct_ctrl_2,
    input wire alu_commit_en, mul_commit_en, div_commit_en, mem_commit_en,
    input wire [4:0] alu_commit_rob_no, mul_commit_rob_no, div_commit_rob_no, mem_commit_rob_no,
    input wire [31:0] alu_commit_value, mul_commit_value, div_commit_value, mem_commit_value,
    input wire [4:0] jal_reg_no,              //跳转指令需要得到的寄存器值 
    output reg [31:0] jal_reg_value,
    output reg [31:0] dm_value_1, dm_value_2, //对于load指令而言，要写入到寄存器中的值
    output reg rs_1_ready, rt_1_ready,        //得到的源寄存器是否就绪的状态
    output reg rs_2_ready, rt_2_ready,
    output reg [31:0] rs_1_value, rt_1_value, //得到的源寄存器的内容
    output reg [31:0] rs_2_value, rt_2_value,
    output reg [4:0] rs_rob_no_1, rt_rob_no_1, rs_rob_no_2, rt_rob_no_2,
    output reg rd_rob_flag_1, rd_rob_flag_2,
    output reg [4:0] rd_rob_no_1, rd_rob_no_2
);
    //32个32位宽的逻辑寄存器
    reg [31:0] logic_reg [0:31];
    //64个32位宽的物理寄存器
    reg [31:0] real_reg [0:63];
    //物理寄存器是否已经写回的标志位
    reg [63:0] real_reg_ok; 
    //定义专用寄存器方便跳转指令jalr使用
    reg [31:0] jal_reg [0:5];
    //物理块空闲队列
    reg [5:0] real_free_queue [0:63];
    reg [5:0] free_head;
    reg [5:0] free_tail;
    //32个逻辑寄存器的映射关系表
    reg [5:0] mapping [0:31][0:15];
    //关系映射表是否在用的标记
    reg [15:0] mapping_use [0:31];
    //映射关系表的头尾指针
    reg [5:0] line_head [0:31];
    reg [5:0] line_tail [0:31];
    reg [5:0] line_count_temp_1, line_count_temp_2;
    //根据rob号检索到物理块号的数组
    reg [5:0] rob_real_no [0:31];
    //根据rob接纳所到逻辑块号的数组
    reg [4:0] rob_logic_no [0:31]; 
    //根据物理块号，查询到rob号的数组
    reg [4:0] real_rob_no [0:63]; 
    //根据物理块号，查询到自身在映射mapping中的位置
    //reg [5:0] real_mapping_index_no [0:63];
    //暂存写入ROB的寄存器值
    reg [31:0] rob_value [0:31];
    //rob中条目是否已经就绪的标志位
    reg [31:0] rob_ok;
    //rob条目是否在使用的标志位
    reg [31:0] rob_use;
    //rob条目反转标志位
    reg [31:0] rob_flag;
    reg rob_item_flag_1, rob_item_flag;
    //rob所要用到的指针
    reg [4:0] rob_tail, rob_head;
    reg [5:0] alu_real_reg_no, mul_real_reg_no, div_real_reg_no;
    reg [5:0] alu_logic_reg_no, mul_logic_reg_no, div_logic_reg_no;

    //find_map表示当前逻辑寄存器映射到的物理寄存器的映射关系表
    reg [5:0] find_map [0:31];
    //在第二阶段映射被替换出来的物理块的使用状态
    reg find_map_pre_use_1_stage2, find_map_pre_use_2_stage2;
    //在第二阶段映射被替换出来的物理块
    reg [5:0] find_map_pre_1_stage2, find_map_pre_2_stage2;
    //在第二阶段映射被替换出来的物理块的就绪状态
    reg find_map_pre_ok_1_stage2, find_map_pre_ok_2_stage2;
    //使用状态寄存器，用来表示find_map中条目的使用状态和就绪状态
    reg [31:0] find_map_use, find_map_ok;

    integer i, j, k;
    
    // 初始化关系映射表
    initial begin
        //初始化空闲块队列
        free_head <= 0;
        free_tail <= 63;
        //初始化rob
        rob_head <= 0;
        rob_tail <= 0;
        rob_ok <= 32'h00000000;
        rob_use <= 32'h00000000;
        real_reg_ok <= 64'h0000000000000000;
        find_map_use <= 32'h00000000;
        find_map_ok <= 32'h00000000;
        rob_flag <= 32'h00000000;
        rob_item_flag_1 <= 1'b0;
        rob_item_flag <= 1'b0;
        for (i=0; i<64; i=i+1) begin
            if (i < 32) begin
                //将每一个映射链头尾指针都初始化成0，即当前映射关系表为空
                line_head[i] <= 0;
                line_tail[i] <= 0;
                mapping_use[i] <= 16'h0000;
            end
            
            real_free_queue[i] <= i;
        end
    end

    //第一阶段生成的目标寄存器映射信号
    reg [5:0] rd_1_mp_stage1, rd_2_mp_stage1;
    reg rd_1_vld_stage1, rd_2_vld_stage1;
    //第一阶段需要向后传递的一些信号
    reg [4:0] rd_2_stage1, rd_1_stage1, rs_2_stage1, rt_2_stage1, rs_1_stage1, rt_1_stage1;
    reg load_direct_en_1_stage1, load_direct_en_2_stage1;
    reg [31:0] imm_1_stage1, imm_2_stage1;
    //第二阶段生成的目标寄存器的ROB
    reg [4:0] rd_1_rob_stage2, rd_2_rob_stage2;
    reg rd_rob_flag_1_stage2, rd_rob_flag_2_stage2;
    reg [4:0] rd_2_stage2, rd_1_stage2, rs_2_stage2, rt_2_stage2, rs_1_stage2, rt_1_stage2;


    //第一阶段，对目标寄存器的重命名进行资源分配
    always @(posedge clk) begin
        // 分配资源
        if (rd_1>0 && rd_2>0) begin
            //如果两个目标寄存器指向同一个逻辑块，则实际上只需要一个物理块，后面一条指令会覆盖前面的
            if (rd_1!=rd_2) begin
                rd_1_mp_stage1 <= real_free_queue[free_head];
                rd_2_mp_stage1 <= real_free_queue[(free_head+1)%64];
                free_head <= (free_head+2)%64;
            end
            else begin
                rd_2_mp_stage1 <= real_free_queue[free_head];
                free_head <= (free_head+1)%64;
            end

            rd_1_vld_stage1 <= 1;
            rd_2_vld_stage1 <= 1;
        end
        else if (rd_1>0) begin
            rd_1_mp_stage1 <= real_free_queue[free_head];
            free_head <= (free_head+1)%64;
            rd_1_vld_stage1 <= 1;
            rd_2_vld_stage1 <= 0;
        end
        else if (rd_2>0) begin
            rd_2_mp_stage1 <= real_free_queue[free_head];
            free_head <= (free_head+1)%64;
            rd_1_vld_stage1 <= 0;
            rd_2_vld_stage1 <= 1;
        end
        else begin
            // 如果两者都无效，不更新寄存器和空闲指针
            rd_1_vld_stage1 <= 0;
            rd_2_vld_stage1 <= 0;
        end

        rd_2_stage1 <= rd_2;
        rd_1_stage1 <= rd_1;
        rs_2_stage1 <= rs_2;
        rt_2_stage1 <= rt_2;
        rs_1_stage1 <= rs_1;
        rt_1_stage1 <= rt_1;
        load_direct_en_1_stage1 <= rob_save_direct_ctrl_1;
        load_direct_en_2_stage1 <= rob_save_direct_ctrl_2;
        imm_1_stage1 <= imm_1;
        imm_2_stage1 <= imm_2;
    end

    //第二阶段，对目标寄存器进行重命名
    always @(posedge clk) begin
        if (rd_1_vld_stage1 && rd_2_vld_stage1) begin
            //$display("RD: ",rd_2_stage1," MP:",rd_2_mp_stage1);
            //如果rd2已经存在了一个映射，将旧的映射暂存备用
            if (find_map_use[rd_2_stage1]) begin
                find_map_pre_2_stage2 <= find_map[rd_2_stage1];
                find_map_pre_ok_2_stage2 <= find_map_ok[rd_2_stage1];
                find_map_pre_use_2_stage2 <= find_map_use[rd_2_stage1];
            end
            else begin
                find_map_pre_2_stage2 <= 0;
                find_map_pre_ok_2_stage2 <= 0;
            end
            find_map[rd_2_stage1] <= rd_2_mp_stage1;
            find_map_use[rd_2_stage1] <= 1;
            find_map_ok[rd_2_stage1] <= 0;

            //如果rd1已经存在了一个映射，将旧的映射暂存备用
            if (find_map_use[rd_1_stage1]) begin
                find_map_pre_1_stage2 <= find_map[rd_1_stage1];
                find_map_pre_ok_1_stage2 <= find_map_ok[rd_1_stage1];
                find_map_pre_use_1_stage2 <= find_map_use[rd_1_stage1];
            end
            else begin
                find_map_pre_1_stage2 <= 0;
                find_map_pre_ok_1_stage2 <= 0;
            end

            //如果两个指令的目标寄存器不一样，则需要给第一条指令的RD分配一个物理块
            if (rd_1_stage1 != rd_2_stage1) begin
                find_map[rd_1_stage1] <= rd_1_mp_stage1;
                find_map_use[rd_1_stage1] <= 1;
                find_map_ok[rd_1_stage1] <= 0;
                //$display("RD: ",rd_1_stage1," MP:",rd_1_mp_stage1);
            end

            //给rd_1分配ROB
            if (load_direct_en_1_stage1==1) begin
                //$display("RD: ", rd_1_mp_stage2, " 已经就绪");
                if (rd_1_stage1 != rd_2_stage1) begin
                    //$display("RD: ", rd_1_stage1, " MPRD: ", rd_1_mp_stage1, " 值:", imm_1_stage1);
                    //直接把立即数写入到物理块
                    real_reg[rd_1_mp_stage1] <= imm_1_stage1;
                    //标记当前物理块已经准备就绪
                    find_map_ok[rd_1_stage1] <= 1;
                end
            end
            else begin
                //分配ROB -- 第一条指令可能没有物理块
                if (rd_1_stage1 != rd_2_stage1) begin
                    rob_real_no[rob_tail]<= rd_1_mp_stage1;
                    real_rob_no[rd_1_mp_stage1] <= rob_tail;
                end
                rd_1_rob_stage2 <= rob_tail;
                rob_logic_no[rob_tail] <= rd_1_stage1;
                rob_ok[rob_tail] <= 0;
                rob_use[rob_tail]<= 1;
                rd_rob_flag_1_stage2 <= rob_item_flag;
            end

            //给rd_2分配ROB
            if (load_direct_en_2_stage1==1) begin
                //$display("RD: ", rd_2_stage1, " MPRD: ", rd_2_mp_stage1, " 值:", imm_2_stage1);
                //直接把立即数写入到物理块
                real_reg[rd_2_mp_stage1] <= imm_2_stage1;
                find_map_ok[rd_2_stage1] <= 1;
            end
            else begin
                //分配ROB
                rd_2_rob_stage2 <= (rob_tail+1)%32;
                rob_real_no[(rob_tail+1)%32] <= rd_2_mp_stage1;
                rob_logic_no[(rob_tail+1)%32]<= rd_2_stage1;
                real_rob_no[rd_2_mp_stage1] <= (rob_tail+1)%32;
                rob_ok[(rob_tail+1)%32] <= 0;
                rob_use[(rob_tail+1)%32] <= 1;
                if (rob_tail==31) begin
                    rd_rob_flag_2_stage2 <= ~rob_item_flag;
                end
                else begin
                    rd_rob_flag_2_stage2 <= rob_item_flag;
                end
            end
            
            if (!load_direct_en_2_stage1 && !load_direct_en_1_stage1) begin
                //如果两条指令不是li指令，rob指针向后移动两位
                rob_tail <= (rob_tail+2)%32;
                if (rob_tail==30 || rob_tail==31) begin
                    rob_item_flag <= ~rob_item_flag;
                end
            end
            
            if (!load_direct_en_2_stage1 && load_direct_en_1_stage1) begin
                //如果第一条指令不是li指令，rob指针向后移动一位
                rob_tail <= (rob_tail+1)%32;
                if (rob_tail==31) begin
                    rob_item_flag <= ~rob_item_flag;
                end
            end

            if (load_direct_en_2_stage1 && !load_direct_en_1_stage1) begin
                //如果第二条指令不是li指令，rob指针向后移动一位
                rob_tail <= (rob_tail+1)%32;
                if (rob_tail==31) begin
                    rob_item_flag <= ~rob_item_flag;
                end
            end
        end
        else if (rd_1_vld_stage1) begin
            //$display("RD: ",rd_1_stage1," MP:",rd_1_mp_stage1);
            find_map[rd_1_stage1] <= rd_1_mp_stage1;
            find_map_use[rd_1_stage1] <= 1;
            find_map_ok[rd_1_stage1] <= load_direct_en_1_stage1==1 ? 1 : 0;

            //只需要给rd_1分配ROB
            if (load_direct_en_1_stage1==1) begin
                //直接把立即数写入到物理块
                real_reg[rd_1_mp_stage1] = imm_1_stage1;
            end
            else begin
                //将物理块写入到rob
                rd_1_rob_stage2 <= rob_tail;
                rob_real_no[rob_tail] <= rd_1_mp_stage1;
                rob_logic_no[rob_tail] <= rd_1_stage1;
                real_rob_no[rd_1_mp_stage1] <= rob_tail;
                rob_ok[rob_tail] <= 0;
                rob_use[rob_tail] <= 1;
                rd_rob_flag_1_stage2 <= rob_item_flag;
                //rob指针向后移动
                rob_tail <= (rob_tail+1)%32;
                if (rob_tail==31) begin
                    rob_item_flag <= ~rob_item_flag;
                end
            end
        end
        else if (rd_2_vld_stage1) begin
            //$display("RD: ",rd_2_stage1," MP:",rd_2_mp_stage1);
            find_map[rd_2_stage1] <= rd_2_mp_stage1;
            find_map_use[rd_2_stage1] <= 1;
            find_map_ok[rd_2_stage1] <= load_direct_en_2_stage1==1 ? 1 : 0;

            //只需要给rd_2分配ROB
            if (load_direct_en_2_stage1==1) begin
                //直接把立即数写入到物理块
                real_reg[rd_2_mp_stage1] <= imm_2_stage1;
            end
            else begin
                //将物理块写入到rob
                rd_2_rob_stage2 <= rob_tail;
                rob_real_no[rob_tail] <= rd_2_mp_stage1;
                rob_logic_no[rob_tail] <= rd_2_stage1;
                real_rob_no[rd_2_mp_stage1] <= rob_tail;
                rob_ok[rob_tail] <= 0;
                rob_use[rob_tail] <= 1;
                //rob指针向后移动
                rob_tail <= (rob_tail+1)%32;
                if (rob_tail==31) begin
                    rd_rob_flag_2_stage2 <= ~rob_item_flag;
                end
            end
        end

        rd_2_stage2 <= rd_2_stage1;
        rd_1_stage2 <= rd_1_stage1;
        rs_2_stage2 <= rs_2_stage1;
        rt_2_stage2 <= rt_2_stage1;
        rs_1_stage2 <= rs_1_stage1;
        rt_1_stage2 <= rt_1_stage1;
    end

    //第三阶段，对指令的源寄存器进行重命名
    always @(posedge clk) begin
        if (rs_1_stage2>0) begin
            if (rs_1_stage2==rd_1_stage2 && find_map_pre_use_1_stage2) begin
                //检查是否存在指令内依赖
                //如果存在，这个时候需要将依赖关系改成之前被替换出的保留站
                if (find_map_pre_ok_1_stage2) begin
                    //以前数据已存在
                    rs_1_value <= real_reg[find_map_pre_1_stage2];
                    rs_1_ready <= 1;
                end
                else begin
                    //以前数据未就绪
                    rs_rob_no_1 <= real_rob_no[find_map_pre_1_stage2];
                    rs_1_ready <= 0;
                end
            end
            else if (rs_1_stage2==rd_2_stage2 && find_map_pre_use_2_stage2) begin
                //检查是否存在指令间依赖
                if (find_map_pre_ok_2_stage2) begin
                    //数据已经就绪，但是前面被替换掉了
                    rs_1_value <= real_reg[find_map_pre_2_stage2];
                    rs_1_ready <= 1;
                end
                else begin
                    //以前那个数据未就绪
                    rs_rob_no_1 <= real_rob_no[find_map_pre_2_stage2];
                    rs_1_ready <= 0;
                end
            end
            else begin
                //查找find_map确定源寄存器依赖的ROB
                if (find_map_ok[rs_1_stage2]) begin
                    //寄存器准备好了
                    rs_1_value <= real_reg[find_map[rs_1_stage2]];
                    rs_1_ready <= 1;
                end
                else if (rob_ok[real_rob_no[find_map[rs_1_stage2]]]) begin
                    //寄存器没有准备好，但是内容已经在rob中了
                    rs_1_value <= rob_value[real_rob_no[find_map[rs_1_stage2]]];
                    rs_1_ready <= 1;
                end
                else begin
                    //寄存器未就绪
                    rs_rob_no_1 <= real_rob_no[find_map[rs_1_stage2]];
                    rs_1_ready <= 0;
                end
            end
        end

        if (rt_1_stage2>0) begin
            if (rt_1_stage2==8) begin
                //$display("ROB: ", rd_1_rob_stage2, " OK: ",find_map_ok[rt_1_stage2]," -map: ", real_rob_no[find_map[rt_1_stage2]]);
            end
            if (rt_1_stage2==rd_1_stage2 && find_map_pre_use_1_stage2) begin
                //检查是否存在指令内依赖
                //如果存在，这个时候需要将依赖关系改成之前被替换出的保留站
                if (find_map_pre_ok_1_stage2) begin
                    //以前数据已存在
                    rt_1_value <= real_reg[find_map_pre_1_stage2];
                    rt_1_ready <= 1;
                end
                else begin
                    //以前数据未就绪
                    rt_rob_no_1 <= real_rob_no[find_map_pre_1_stage2];
                    rt_1_ready <= 0;
                end
            end
            else if (rt_1_stage2==rd_2_stage2 && find_map_pre_use_2_stage2) begin
                //检查是否存在指令间依赖
                if (find_map_pre_ok_2_stage2) begin
                    //数据已经就绪，但是前面被替换掉了
                    rt_1_value <= real_reg[find_map_pre_2_stage2];
                    rt_1_ready <= 1;
                end
                else begin
                    //以前那个数据未就绪
                    rt_rob_no_1 <= real_rob_no[find_map_pre_2_stage2];
                    rt_1_ready <= 0;
                end
            end
            else begin
                //查找find_map确定源寄存器依赖的ROB
                if (find_map_ok[rt_1_stage2]) begin
                    //寄存器准备好了
                    rt_1_value <= real_reg[find_map[rt_1_stage2]];
                    rt_1_ready <= 1;
                end
                else if (rob_ok[real_rob_no[find_map[rt_1_stage2]]]) begin
                    //寄存器没有准备好，但是内容已经在rob中了
                    rt_1_value <= rob_value[real_rob_no[find_map[rt_1_stage2]]];
                    rt_1_ready <= 1;
                end
                else begin
                    //寄存器未就绪
                    rt_rob_no_1 <= real_rob_no[find_map[rt_1_stage2]];
                    rt_1_ready <= 0;
                end
            end
        end

        if (rs_2_stage2>0) begin
            if (rs_2_stage2==rd_1_stage2) begin
                //如果存在指令间依赖
                rs_2_ready <= 0;
                rs_rob_no_2 <= rd_1_rob_stage2;
            end
            else if (rs_2_stage2==rd_2_stage2 && find_map_pre_use_2_stage2) begin
                //检查是否存在指令内依赖
                //$display("替换出来的: ", find_map_pre_2_stage2);
                //如果存在，这个时候需要将依赖关系改成之前被替换出的保留站
                if (find_map_pre_ok_2_stage2) begin
                    //以前数据已存在
                    rs_2_value <= real_reg[find_map_pre_2_stage2];
                    rs_2_ready <= 1;
                end
                else begin
                    //以前数据未就绪
                    rs_rob_no_2 <= real_rob_no[find_map_pre_2_stage2];
                    rs_2_ready <= 0;
                end
            end
            else begin
                //查找find_map确定源寄存器依赖的ROB
                if (find_map_ok[rs_2_stage2]) begin
                    //寄存器准备好了
                    rs_2_value <= real_reg[find_map[rs_2_stage2]];
                    rs_2_ready <= 1;
                end
                else begin
                    //寄存器未就绪
                    rs_rob_no_2 <= real_rob_no[find_map[rs_2_stage2]];
                    rs_2_ready <= 0;
                end
            end
        end

        if (rt_2_stage2>0) begin
            if (rt_2_stage2==rd_1_stage2) begin
                //检查是否存在指令间依赖
                rt_rob_no_2 <= rd_1_rob_stage2;
                rt_2_ready <= 0;
            end
            else if (rt_2_stage2==rd_2_stage2 && find_map_pre_use_2_stage2) begin
                //检查是否存在指令内依赖
                //如果存在，这个时候需要将依赖关系改成之前被替换出的保留站
                if (find_map_pre_ok_2_stage2) begin
                    //以前数据已存在
                    rt_2_value <= real_reg[find_map_pre_2_stage2];
                    rt_2_ready <= 1;
                end
                else begin
                    //以前数据未就绪
                    rt_rob_no_2 <= real_rob_no[find_map_pre_2_stage2];
                    rt_2_ready <= 0;
                end
            end
            else begin
                //查找find_map确定源寄存器依赖的ROB
                if (find_map_ok[rt_2_stage2]) begin
                    //寄存器准备好了
                    rt_2_value <= real_reg[find_map[rt_2_stage2]];
                    rt_2_ready <= 1;
                end
                else if (rob_ok[real_rob_no[find_map[rt_2_stage2]]]) begin
                    //寄存器没有准备好，但是内容已经在rob中了
                    rt_2_value <= rob_value[real_rob_no[find_map[rt_2_stage2]]];
                    rt_2_ready <= 1;
                end
                else begin
                    //寄存器未就绪
                    rt_rob_no_2 <= real_rob_no[find_map[rt_2_stage2]];
                    rt_2_ready <= 0;
                end
            end
        end

        rd_rob_no_1 <= rd_1_rob_stage2;
        rd_rob_no_2 <= rd_2_rob_stage2;
        rd_rob_flag_1 <= rd_rob_flag_1_stage2;
        rd_rob_flag_2 <= rd_rob_flag_2_stage2;
    end

    //ROB内容的写回和物理寄存器的更新
    // always @(posedge clk) begin
    //     //检查rob是否可以按顺序写回 -- 这样写有一个问题，那就是一个时钟只能更新一个
    //     for (i=0; i<32; i=i+1) begin
    //         // 当前ROB条目为可用状态且位于头部，可以更新到物理寄存器
    //         if (rob_ok[i] && i==rob_head) begin
    //             //如果映射表中逻辑块对应的物理块是当前rob对应的物理块，则更新
    //             if (find_map[rob_logic_no[i]]==rob_real_no[i]) begin
    //                 real_reg[rob_real_no[i]] <= rob_value[i];
    //                 find_map_ok[rob_logic_no[i]] <= 1;
    //             end
                
    //             // 无论最终的结果是否能写回物理块，这里的ROB块都需要被释放了
    //             rob_head <= (rob_head+1)%32;
    //             rob_ok[i] <= 0;
    //         end
    //     end
    // end
endmodule